package test;

import utils.FileUtil;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;

public class ImageMosaic {
    private static final String opt_mosaic = "mosaic";
    private static final String opt_scale = "scale";

    public static void main(String[] args) {
        loadImg(FileUtil.RESOURCES + "imgs/flower.jpg",
                System.currentTimeMillis(),
                50,
                opt_mosaic,
                2);
    }

    public static void createImg(int[][] arr, Object name) {
        int width = arr[0].length;
        int height = arr.length;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                image.setRGB(j, i, arr[i][j]);
            }
        }
        File output = new File(FileUtil.RESOURCES + "trans/" + name + ".jpg");
        try {
            ImageIO.write(image, "jpg", output);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static int[][] doScale(int[][] arr, int scale) {
        int newWidth = arr[0].length / scale;
        int newHeight = arr.length / scale;
        int[][] res = new int[newHeight][newWidth];
        for (int i = 0; i < newHeight; i++) {
            for (int j = 0; j < newWidth; j++) {
                res[i][j] = averageScale(arr, i * scale, j * scale, scale);
            }
        }
        return res;
    }

    public static int averageScale(int[][] arr, int i, int j, int scale) {
        int width = arr[0].length;
        int height = arr.length;
        int a = 0, b = 0, c = 0;
        int divided = scale * scale;
        for (int x = 0; x < scale && i + x < height; x++) {
            for (int y = 0; y < scale && j + y < width; y++) {
                int temp = arr[i + x][j + y];
                a += (temp >> 16) & 0xff;
                b += (temp >> 8) & 0xff;
                c += temp & 0xff;
            }
        }
        return rgbToColor(a / divided, b / divided, c / divided);
    }

    public static int[][] doMosaic(int[][] arr, int scale, int mode) {
        int newWidth = arr[0].length / scale;
        int newHeight = arr.length / scale;
        int[][] res = Arrays.copyOf(arr, arr.length);
        for (int i = 0; i < newHeight; i++) {
            for (int j = 0; j < newWidth; j++) {
                mosaicScale(res, i * scale, j * scale, scale, mode);
            }
        }
        return res;
    }

    /**
     * 默认方式二
     * 方式一：几个点色度值求出现次数最多的，并将全部点设置为同一值
     * 方式二：直接指定某一个点的色度值，并将全部点设置为同一值
     * 方式三：求平均值，并将全部点设置为同一值
     */
    public static void mosaicScale(int[][] arr, int i, int j, int scale, int mode) {
        int width = arr[0].length;
        int height = arr.length;
        if (mode == 1) {

        } else if (mode == 2) {

            int avg = arr[i][j];
            for (int x = 0; x < scale && i + x < height; x++) {
                for (int y = 0; y < scale && j + y < width; y++) {
                    arr[i + x][j + y] = avg;
                }
            }
        } else if (mode == 3) {
            int avgColor = averageScale(arr, i, j, scale);
            for (int x = 0; x < scale && i + x < height; x++) {
                for (int y = 0; y < scale && j + y < width; y++) {
                    arr[i + x][j + y] = avgColor;
                }
            }
        }
    }

    public static int[][] imgDataReshapeList(int[][] data, int scale, String opt, int mode) {
        if (Objects.equals(opt, opt_mosaic)) {
            return doMosaic(data, scale, mode);
        } else if (Objects.equals(opt, opt_scale)) {
            return doScale(data, scale);
        } else {
            return new int[][]{};
        }
    }

    public static void loadImg(String path, Object name, int scale, String opt, int mode) {
        try {
            File file = new File(path);
            BufferedImage img = ImageIO.read(file);
            int width = img.getWidth();
            int height = img.getHeight();
            int[][] data = new int[height][width];
            for (int y = 0; y < height; y++) {
                data[y] = new int[width];
                for (int x = 0; x < width; x++) {
                    data[y][x] = img.getRGB(x, y);
                }
            }
            int[][] reshapedData = imgDataReshapeList(data, scale, opt, mode);
            createImg(reshapedData, opt + "_" + scale + "_" + name);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static int rgbToColor(int r, int g, int b) {
        return (r << 16) + (g << 8) + b;
    }
}